SPB Git

Repository Public

route.ts 3.5 KB 105 lines typescript

1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// /api/admin/team/[id] — gestion d'un compte admin (super_admin seulement) :3// rôles, activation, nom, courriel, réinitialisation du mot de passe.4// Garde-fous : impossible de se désactiver soi-même ou de retirer le dernier5// super_admin actif.6import { NextRequest, NextResponse } from "next/server";7import {8  findAdminById,9  listAdmins,10  setAdminPassword,11  updateAdmin,12} from "@/lib/comms/db";13import {14  getAdminSession,15  isSuperAdmin,16  parseRoles,17  ADMIN_ROLES,18} from "@/lib/comms/admin-auth";1920function lastActiveSuperAdmin(targetId: number): boolean {21  const remaining = listAdmins().filter(22    (a) => a.id !== targetId && a.active && parseRoles(a.roles).includes("super_admin"),23  );24  return remaining.length === 0;25}2627export async function PATCH(28  req: NextRequest,29  { params }: { params: Promise<{ id: string }> },30) {31  const session = await getAdminSession();32  if (!session)33    return NextResponse.json({ error: "Non autorisé." }, { status: 401 });34  if (!isSuperAdmin(session))35    return NextResponse.json({ error: "Réservé au super administrateur." }, { status: 403 });36  const id = Number((await params).id);37  const target = Number.isInteger(id) ? findAdminById(id) : undefined;38  if (!target)39    return NextResponse.json({ error: "Compte introuvable." }, { status: 404 });4041  const body = (await req.json().catch(() => null)) as {42    display_name?: string;43    email?: string | null;44    roles?: string[];45    active?: boolean;46    password?: string;47  } | null;48  if (!body)49    return NextResponse.json({ error: "Requête illisible." }, { status: 400 });5051  if (body.roles !== undefined) {52    const roles = body.roles.filter((r) => r in ADMIN_ROLES);53    if (!roles.length)54      return NextResponse.json({ error: "Au moins un rôle requis." }, { status: 422 });55    if (56      parseRoles(target.roles).includes("super_admin") &&57      !roles.includes("super_admin") &&58      lastActiveSuperAdmin(target.id)59    )60      return NextResponse.json(61        { error: "Impossible de retirer le dernier super administrateur." },62        { status: 422 },63      );64    updateAdmin(target.id, { roles });65  }66  if (body.active !== undefined) {67    if (target.id === session.id && !body.active)68      return NextResponse.json(69        { error: "Impossible de désactiver votre propre compte." },70        { status: 422 },71      );72    if (73      !body.active &&74      parseRoles(target.roles).includes("super_admin") &&75      lastActiveSuperAdmin(target.id)76    )77      return NextResponse.json(78        { error: "Impossible de désactiver le dernier super administrateur." },79        { status: 422 },80      );81    updateAdmin(target.id, { active: body.active });82  }83  if (body.display_name !== undefined) {84    const dn = body.display_name.trim().slice(0, 120);85    if (!dn)86      return NextResponse.json({ error: "Nom d'affichage requis." }, { status: 422 });87    updateAdmin(target.id, { display_name: dn });88  }89  if (body.email !== undefined)90    updateAdmin(target.id, {91      email: body.email ? body.email.trim().slice(0, 200) : null,92    });93  if (body.password !== undefined) {94    if (body.password.length < 8)95      return NextResponse.json(96        { error: "Mot de passe trop court (8 caractères minimum)." },97        { status: 422 },98      );99    // Change le mot de passe ET invalide toutes les sessions du compte100    // (l'empreinte pwv du jeton ne correspond plus).101    setAdminPassword(target.id, body.password);102  }103  return NextResponse.json({ ok: true });104}105
Files main
Menu

Theme